
#pragma once

#include "type.h"
#include "equipment.h"
#include "formation.h"
#include "gameaction.h"
#include "CCSkeletalAnimation.h"
#include <string>

namespace cocos2d {
class CCSkeletalSprite;
}

class Bullet;
class Army;
class GameScene;

class Unit {
public:
	Unit();
	virtual ~Unit();

	virtual void update(float ticks);
	virtual void init(UnitInfo const & info, float unitScale);

	void changeEquipment(const UnitInfo& info);
	void setPosition(const CCPoint& pos);
	void addBullet(Bullet* bullet);
	void transformState(UnitState newState);

	virtual void assignTo(const CCPoint& pos, int lineIndex, int rowIndex);
	virtual void moveTo(const CCPoint& pos);
	virtual void runTo(const CCPoint& pos);
	virtual void startAttack();

	bool isAlive() const {
		return state != UnitState::dying && state != UnitState::died;
	}

	bool isWalking() const {
		return state == UnitState::walk || state == UnitState::walk_aim || state == UnitState::walk_attack || state == UnitState::walk_reload;
	}

	bool isAttacking() const {
		return state == UnitState::attack || state == UnitState::walk_attack;
	}

	bool isReloading() const {
		return state == UnitState::reload || state == UnitState::walk_reload;
	}

	bool isStandby() const {
		return state == UnitState::idle || state == UnitState::aim;
	}

	int getGlobalLineIndex() const {
		return gridInfo.squadIndex * LINES_PER_SQUAD + gridInfo.lineIndex;
	}

	static int getRangeBetweenUnits(const Unit* a, const Unit* b);
	static bool isNormalUnit(const string& name);
	static string getSkeletonFileName(const UnitInfo& info);

	static bool isStandbyState(UnitState theState) {
		return theState == UnitState::idle || theState == UnitState::aim;
	}

	static bool isAttackingState(UnitState theState) {
		return theState == UnitState::attack || theState == UnitState::walk_attack;
	}

	static bool isReloadingState(UnitState theState) {
		return theState == UnitState::reload || theState == UnitState::walk_reload;
	}

	static bool isWalkingState(UnitState theState) {
		return theState == UnitState::walk || theState == UnitState::walk_aim || theState == UnitState::walk_attack || theState == UnitState::walk_reload;
	}

	void applyBullet(Bullet* bullet) {
		onBulletHit(bullet);
	}

public:
	static int ID_SEED;
	int id;

	string skeletonName;

	UnitInfo unitInfo;
	GridInfo gridInfo;
	GridInfo oldGridInfo;
	GridInfo targetGridInfo;

	CCPoint speed;
	float scale;

	CreatureType creatureType;
	UnitState state;
	UnitState previousState;
	ArmyFaction faction;

	bool arrivedTargetPosition;
	bool isAssigning;

	Army* ourArmy;
	Army* theirArmy;

	Unit* target;

	EquipmentAttribute attribute;

	const EquipmentAttribute* creature;
	const EquipmentAttribute* weapon;
	const EquipmentAttribute* armor;
	const EquipmentAttribute* shield;
	const EquipmentAttribute* special;

	CCPoint position;
	CCPoint previousPosition;
	CCPoint targetPosition;

	cocos2d::CCSkeletalSprite* sprite;
	GameScene* gameScene;

	list<EquipmentAction> actions;

protected:
	virtual void handleStateBirth(float ticks){};
	virtual void handleStateAim(float ticks){};
	virtual void handleStateAttack(float ticks){};
	virtual void handleStateDying(float ticks){};
	virtual void handleStateIdle(float ticks){};
	virtual void handleStateReload(float ticks){};
	virtual void handleStateWalk(float ticks){};
	virtual void handleStateAssign(float ticks) {};
	virtual void handleStateWalkAim(float ticks){};
	virtual void handleStateWalkAttack(float ticks){};
	virtual void handleStateWalkReload(float ticks){};

	virtual void handleActions(EquipmentActionTriggerType triggerType);

	virtual void onEnterState(UnitState theState);
	virtual void onExitState(UnitState theState);

	virtual Unit *findDistantOpponent();

	virtual void updateAttribute();
	virtual void updateSpritePosition();
	virtual void updateActions(float ticks);
	virtual void updateBullets(float ticks);
	virtual void updateGridInfo();

	void applyActionModifier(const EquipmentAction& action, Unit* target);
	vector<Unit *> getActionTargets(EquipmentActionTargetType targetType, int actionValue = 0);

	virtual void onSpineEvent(const SpineEvents* event);
	virtual void onAttack();
	virtual void onBulletHit(Bullet* bullet);

	void move(float ticks);

protected:
	float _timeElapsed;
	list<Bullet*> _bullets;

	CCLabelTTF *_labelDebugInfo;
	char buf[100];

	static const int UNIT_SPEED = 30;

	bool _shouldUpdateGridInfo;

	float fadeOutTime;
	float fadeInTime;

	float fadeOutDelay;
	float fadeInDelay;

private:

};